import * as path from "path";
import { EventSystem } from "./Core/Module/EventSystem/EventSystem";
import { IdGenerater } from "./Core/Module/IdGenerater/IdGenerater";
import { Logger } from "./Core/Module/Log/Logger";
import { TimeInfo } from "./Core/Module/Time/TimeInfo";
import { TimerComponent } from "./Core/Module/Timer/TimerComponent";
import { Game } from "./Core/Singleton/Game";
import { GetAssemblyTypes, Sleep } from "./Decorator/Decorator";
import { Entry } from "./Codes/Model/Share/Entry";
import { AppType, Options } from "./Core/Module/Options/Options";
import { CoroutineLockComponent } from "./Core/Module/CoroutineLock/CoroutineLockComponent";
import { ObjectPool } from "./Core/Module/ObjectPool/ObjectPool";
import { GlobalExtentions } from "./Support/Share/Extentions/GlobalExtentions";
import { LoadModules, LoadFiles } from "./Support/Server/Loader/CodeLoader";
import { CodePreLoader } from "./Support/Server/Loader/CodePreLoader";
import { GetAllConfig } from "./Support/Server/Loader/ConfigLoader";
import { ServerUtil } from "./ServerUtil";

export class Program {

    dumpRequire() {
        for (let key in require) {
            let rmodel = require[key];
            console.log(`===== ${key}`);
            for (let rkey in rmodel) {
                console.log(rkey);
            }
        }
    }

    async init() {
        GetAllConfig;
        GlobalExtentions.Create();

        Game.AddSingleton<Options>(Options);

        Options.Instance.AppType = AppType.Server;
        Options.Instance.Process = 1;
        Options.Instance.Console = 1;
        Options.Instance.StartConfig = "StartConfig/Localhost";

        Game.AddSingleton<TimeInfo>(TimeInfo);
        Game.AddSingleton<Logger>(Logger);
        Game.AddSingleton<ObjectPool>(ObjectPool);
        Game.AddSingleton<IdGenerater>(IdGenerater);
        Game.AddSingleton<EventSystem>(EventSystem);
        Game.AddSingleton<TimerComponent>(TimerComponent);
        Game.AddSingleton<CoroutineLockComponent>(CoroutineLockComponent);

        let types = GetAssemblyTypes();
        EventSystem.Instance.Add(types);

        Entry.Init();
        Entry.Start();
    }

    async Start() {
        console.log(`Program Start.`);

        ServerUtil.Init();

        const filePathList = CodePreLoader.GetFilePathList();

        console.log(`Load Core.`);
        await LoadModules(path.join(__dirname, "Core"));

        console.log(`Load Model.`);
        await LoadModules(path.join(__dirname, "Codes/Model/Generate"));
        await LoadModules(path.join(__dirname, "Codes/Model/Share"));
        await LoadModules(path.join(__dirname, "Codes/Model/Server"));

        console.log(`PreLoad Code.`);
        await LoadFiles(__dirname, filePathList);

        console.log(`Load Hotfix.`);
        await LoadModules(path.join(__dirname, "Codes/Hotfix/Share"));
        await LoadModules(path.join(__dirname, "Codes/Hotfix/Server"));

        console.log(`Game Init.`);
        await this.init();

        console.log(`Game Update.`);
        while (true) {
            await Sleep(1);
            try {
                Game.Update();
                Game.LateUpdate();
                Game.FrameFinishUpdate();
            } catch (e) {
                console.error(e);
            }
        }
    }

    static Main(): void {
        new Program().Start();
    }
}

Program.Main();